import os, sys
import socket
import time
from paramiko.client import SSHClient, AutoAddPolicy
from paramiko.ssh_exception import AuthenticationException
from concurrent.futures import ThreadPoolExecutor
from threading import Lock


def get_local_ip_using_udp():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("255.255.255.255", 1))
        IP = s.getsockname()[0]
    finally:
        s.close()
    return IP


def get_ip_address(iface):
    import netifaces
    
    try:
        # 获取指定接口的信息
        addrs = netifaces.ifaddresses(iface)
        # 获取IPv4地址信息
        ipv4_info = addrs.get(netifaces.AF_INET)
        if ipv4_info is not None:
            # 返回第一个IPv4地址（通常是我们想要的）
            return ipv4_info[0]["addr"]
    except ValueError:
        return None


def get_all_local_ip():
    import netifaces

    # 获取所有网络接口的列表
    interfaces = netifaces.interfaces()

    # 打印所有接口名称
    local_addresses = []
    for iface in interfaces:
        # print(iface)
        result = get_ip_address(iface)
        if result is None:
            continue
        if result == "127.0.0.1":
            continue
        local_addresses.append(result)
    return local_addresses


def check_ssh_port(host_ip, port=22, timeout=1, username="pi", password="raspberry"):
    try:
        ssh_client = SSHClient()
        ssh_client.set_missing_host_key_policy(AutoAddPolicy())
        ssh_client.connect(host_ip, port=22, username=username, password=password, timeout=timeout)
        ssh_client.close()
        return True
    except Exception as e:
        return False


def scan_port(ip, port, timeout=1):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)  # 设置超时时间
    result = sock.connect_ex((ip, port))
    sock.close()
    return True if result == 0 else False


def thread_scan_port(host_ip, port, scan_func, lock, remote_addresses):
    result = scan_func(host_ip, port)
    if result:
        lock.acquire()
        remote_addresses.append(host_ip)
        lock.release()


def scan_all_ssh_port(local_addresses):
    port = 22  # ssh 端口号

    remote_addresses = []
    lock = Lock()
    executor = ThreadPoolExecutor(max_workers=255)

    # 扫描所有ssh的22端口, 不检查账号和密码
    for local_ip in local_addresses:
        # t0 = time.time()
        futures = []
        index = local_ip.rfind(".")
        target_ip_head = local_ip[:index]
        for i in range(1, 255):
            target_ip = target_ip_head + "." + str(i)

            future = executor.submit(thread_scan_port, target_ip, port, scan_port, lock, remote_addresses)
            futures.append(future)

        for future in futures:
            result = future.result()  # result()方法会阻塞直到任务完成
            # print(result)

        # print(f"{time.time()-t0:.3f}")

    # 用ssh链接检查账号和密码
    # t0 = time.time()
    _remote_addresses = []
    for target_ip in remote_addresses:
        future = executor.submit(thread_scan_port, target_ip, port, check_ssh_port, lock, _remote_addresses)
        futures.append(future)

    for future in futures:
        result = future.result()  # result()方法会阻塞直到任务完成

    # print(f"{time.time()-t0:.3f}")

    # remote_addresses = _remote_addresses
    remote_addresses = list(set(_remote_addresses))  # 去重
    return remote_addresses


################################################################################
if __name__ == "__main__":
    # check_ssh_port("192.168.3.100")
    # print(get_all_local_ip())
    local_addresses = get_all_local_ip()
    # local_addresses = [local_addresses[0]]
    print(scan_all_ssh_port(local_addresses))

    sys.exit(0)
